home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / misc / vitals.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-29  |  10.3 KB  |  333 lines

  1. static char *HPUX_ID = "@(#)27.1   85/02/04";
  2. /* HPUX_ID: @(#)vitals.c        27.1     85/02/04  */
  3. /*
  4.  * Compute vital statistics of data:  crc, sum, line, word, and character
  5.  * counts.  See the manual entry for details.
  6.  *
  7.  * Compile with -DTABLE to produce an alternate program, which prints a
  8.  * CRC table for use in this program.
  9.  *
  10.  * The CRC code was lifted from a USENET posting:
  11.  *
  12.  * hpfcla:net.sources / hcrvax!sft /  8:17 pm  Nov 15, 1984
  13.  *
  14.  * The following program is a command to calculate the CRC of files.
  15.  * It is useful for the same purposes as sum(1).  It calculates the
  16.  * true CRC16 (unlike CP/M utilities that say they calculate CRCs
  17.  * but really just hash).  Crc detects more errors than old sum(1);
  18.  * for example, it detects exchanges of characters.  It is also
  19.  * (now) in the public domain.
  20.  *
  21.  *  CRC16 polynomial: x**0 + x**2 + x**15 + x**16 (0xA001)
  22.  * (CCITT polynomial: x**0 + x**5 + x**12 + x**16 (0x8408))
  23.  * Initial condition: 0
  24.  *
  25.  * D. Hugh Redelmeier, 1983 April 15; latest change: 1984 April 2.
  26.  */
  27.  
  28. #include <stdio.h>
  29.  
  30. char    *USAGE = "usage: %s [-rslwcb] [files...]\n";
  31.  
  32. #define proc                            /* null; easy to grep for procs */
  33. #define chNull     ('\0')
  34. #define chNewline  ('\n')
  35. #define sbNull     ((char *) NULL)
  36. #define fileNull   ((FILE *) NULL)
  37. #define false      0
  38. #define true       1
  39.  
  40. char    *myname;                                /* how command invoked  */
  41. int     rflag = false;                          /* -r (crc) option      */
  42. int     sflag = false;                          /* -s (sum) option      */
  43. int     lflag = false;                          /* -l (lines) option    */
  44. int     wflag = false;                          /* -w (words) option    */
  45. int     cflag = false;                          /* -c (chars) option    */
  46. int     bflag = false;                          /* -b (basenames) opt   */
  47.  
  48. int     retval = 0;                             /* return value          */
  49. char    *defaultargs[] = {"-", sbNull};         /* read stdin by default */
  50.  
  51. #define PrintErr(part1,part2) \
  52.         fprintf (stderr, "%s: %s %s\n", myname, part1, part2);
  53.  
  54. /************************************************************************
  55.  * M A I N
  56.  *
  57.  * Initialize, check arguments, open files, and call another routine to
  58.  * do each file.
  59.  */
  60.  
  61. proc main (argc, argv)
  62. register int    argc;
  63. register char   **argv;
  64. {
  65. extern   int    optind;                 /* for getopt()  */
  66.      int    optchar;                /* from getopt() */
  67. register FILE   *filep;                 /* file to read  */
  68.  
  69. #ifdef TABLE                                    /* just print table */
  70.     PrintTable();
  71. #else
  72.  
  73. /*
  74.  * CHECK ARGUMENTS:
  75.  */
  76.  
  77.     myname = *argv;
  78.  
  79.     while ((optchar = getopt (argc, argv, "rslwcb")) != EOF)
  80.         switch (optchar)
  81.         {
  82.         case 'r':   rflag = true;   break;
  83.         case 's':   sflag = true;   break;
  84.         case 'l':   lflag = true;   break;
  85.         case 'w':   wflag = true;   break;
  86.         case 'c':   cflag = true;   break;
  87.         case 'b':   bflag = true;   break;
  88.         default:    fprintf (stderr, USAGE, myname); exit (1);
  89.         }
  90.  
  91.     if (! (rflag || sflag || lflag || wflag || cflag))
  92.         rflag = sflag = lflag = wflag = cflag = true;
  93.  
  94.     argc -= optind;
  95.     argv += optind;
  96.  
  97.     if (argc < 1)                           /* use default arguments */
  98.         argv = defaultargs;
  99.  
  100. /*
  101.  * OPEN AND DO EACH INPUT FILE:
  102.  *
  103.  * Be careful to keep stdin open for filenames of "-".
  104.  * Argc is not altered; if < 1, it means no file args were given.
  105.  */
  106.  
  107.     for ( ; *argv != sbNull; argv++)                /* each argument */
  108.     {
  109.         if (strcmp (*argv, "-") == 0)               /* read stdin */
  110.         filep = stdin;
  111.  
  112.         else if ((filep = fopen (*argv, "r")) == fileNull)
  113.         {
  114.         PrintErr ("can't open", *argv);
  115.         retval = 1;
  116.         continue;
  117.         }
  118.  
  119.         DoFile (filep, (argc < 1), *argv);
  120.  
  121.         if (filep != stdin)                 /* keep stdin open for reuse */
  122.         fclose (filep);
  123.     }
  124.     exit (retval);
  125.  
  126. #endif /* not TABLE */
  127.  
  128. } /* main */
  129.  
  130. #ifdef TABLE
  131.  
  132. /************************************************************************
  133.  * P R I N T   T A B L E
  134.  *
  135.  * Print table needed for CRC computation, as a C array declaration.
  136.  * The output can then be included in this program.  It would be easy
  137.  * to just build the table in memory each time the program is run, but
  138.  * what the heck -- this way is a little more complicated, but already
  139.  * done, and shaves off a bit of startup time.
  140.  *
  141.  * Assumes unsigned and short are at least 16 bits.
  142.  */
  143.  
  144. proc PrintTable()
  145. {
  146. register unsigned index = 0;            /* place in table       */
  147. register unsigned entry;                /* table entry          */
  148. register int      count;                /* for changing entry   */
  149.  
  150.     printf ("unsigned short CRCtable [256] = {");
  151.  
  152.     while (true)
  153.     {
  154.         if ((index % 8) == 0)               /* time for new line */
  155.         putchar (chNewline);
  156.  
  157.         for (entry = index, count = 8; (count--) > 0; )
  158.         {
  159.         if (entry & 1)                  /* low bit set */
  160.             entry = (entry >> 1) ^ 0xA001;
  161.         else
  162.             entry >>= 1;
  163.         }
  164.  
  165.         printf ("\t0x%4.4x", entry);
  166.  
  167.         if (++index == 256)
  168.         break;
  169.  
  170.         putchar (',');
  171.     }
  172.  
  173.     printf ("\n};\n");
  174.  
  175. } /* PrintTable */
  176.  
  177. #else /* not TABLE */
  178.  
  179. /************************************************************************
  180.  * CRC TABLE AND BYTE SUM STRUCTS
  181.  *
  182.  * CRCtable[], output from PrintTable(), is used for CRC calculation.
  183.  * Structures are used for circular mod-2**16 byte sums.  They assume
  184.  * that two shorts == one long!
  185.  */
  186.  
  187. unsigned short CRCtable [256] = {
  188.     0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
  189.     0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
  190.     0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
  191.     0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
  192.     0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
  193.     0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
  194.     0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
  195.     0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
  196.     0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
  197.     0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
  198.     0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
  199.     0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
  200.     0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
  201.     0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
  202.     0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
  203.     0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
  204.     0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
  205.     0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
  206.     0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
  207.     0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
  208.     0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
  209.     0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
  210.     0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
  211.     0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
  212.     0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
  213.     0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
  214.     0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
  215.     0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
  216.     0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
  217.     0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
  218.     0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
  219.     0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
  220. };
  221.  
  222. struct shorts {                 /* as used, order is irrelevant */
  223.     unsigned short  high, low;
  224. };
  225.  
  226. typedef union {                 /* to map one long to two shorts */
  227.     unsigned long   sum;
  228.     struct   shorts shorts;
  229. } convert;
  230.  
  231. /************************************************************************
  232.  * D O   F I L E
  233.  *
  234.  * Read one file, calculate values, and print an output line.
  235.  * Sets retval if necessary.  ch is int, not char, to be sure
  236.  * it can distinguish 0xff and EOF.  As a result, all normal
  237.  * values of ch should be positive, 0..255.
  238.  */
  239.  
  240. proc DoFile (filep, nullname, filename)
  241. register FILE   *filep;         /* file to read     */
  242.      int    nullname;       /* ignore filename? */
  243.      char   *filename;      /* name of filep    */
  244. {
  245. register int    ch;             /* current char */
  246. register unsigned crc = 0;      /* crc sum      */
  247. register long   sum   = 0L;     /* byte sum     */
  248. register long   lines = 0L;     /* line count   */
  249. register long   words = 0L;     /* word count   */
  250. register long   chars = 0L;     /* char count   */
  251.  
  252.      convert conv;          /* for 16-sum   */
  253. register int notword = true;    /* not in word? */
  254.  
  255. /*
  256.  * READ FILE AND COMPUTE SUMS:
  257.  *
  258.  * CRCtable[] values have 16 bits, so the masking is necessary before each
  259.  * repeated index into the array.  sum is allowed to increment to more than
  260.  * 16 bits; overflow is handled later.  Line and char counts are accumulated
  261.  * regardless whether they are needed; it's faster not to check.  Words are
  262.  * counted in the same strange way as wc(1), ignoring special chars.
  263.  */
  264.  
  265.     while ((ch = getc (filep)) != EOF)
  266.     {
  267.         if (rflag)
  268.         crc = (crc >> 8) ^ (CRCtable [(crc ^ ch) & 0xff]);
  269.  
  270.         if (sflag)
  271.         sum += ch;
  272.  
  273.         if (ch == chNewline)
  274.         lines++;
  275.  
  276.         chars++;
  277.  
  278.         if (wflag)
  279.         {
  280.         if ((' ' < ch) && (ch < '\177'))        /* word char */
  281.         {
  282.             if (notword)                        /* start of word */
  283.             {
  284.             words++;
  285.             notword = false;
  286.             }
  287.         }
  288.         else if ((ch == ' ') || (ch == '\t') || (ch == chNewline))
  289.         {
  290.             notword = true;
  291.         }
  292.         }
  293.     } /* while */
  294.  
  295. /*
  296.  * REPORT ERROR OR PRINT TOTALS:
  297.  */
  298.  
  299.     if (ferror (filep))
  300.     {
  301.         PrintErr ("read failed from", nullname ? "stdin" : filename);
  302.         retval = 1;
  303.     }
  304.     else
  305.     {
  306.         conv.sum = sum;             /* for adding back overflow */
  307.  
  308.         if (rflag)  printf (" %4.4x", crc);
  309.         if (sflag)  printf (" %5u",   conv.shorts.high + conv.shorts.low);
  310.         if (lflag)  printf (" %6ld",  lines);
  311.         if (wflag)  printf (" %6ld",  words);
  312.         if (cflag)  printf (" %6ld",  chars);
  313.  
  314.         if (! nullname)             /* have name to print */
  315.         {
  316.         if (bflag)              /* basename only */
  317.         {
  318.             char *cp = filename;
  319.  
  320.             while (*cp != chNull)       /* till end of name */
  321.             if (*cp++ == '/')       /* directory level  */
  322.                 filename = cp;      /* set past '/'     */
  323.         }
  324.         printf (" %s", filename);
  325.         }
  326.         putchar (chNewline);
  327.  
  328.     } /* else */
  329.  
  330. } /* DoFile */
  331.  
  332. #endif /* not TABLE */
  333.